package handler

import (
	ds "gitee.com/shipnet/flogo_edge_channel_data_store"
	ms "gitee.com/shipnet/flogo_metric_store"
	"github.com/project-flogo/core/data/coerce"
	"github.com/tidwall/gjson"
)

type EdgeChannelState struct {
	Params              EdgeChannelParams   `mapstructure:"params" md:"params" json:"params,omitempty"`
	LastMetricData      *ms.MetricData      `mapstructure:"lastMetricData" md:"lastMetricData" json:"lastMetricData,omitempty"`
	LastEdgeChannelData *ds.EdgeChannelData `mapstructure:"lastEdgeChannelData" md:"lastEdgeChannelData" json:"lastEdgeDhannelData,omitempty"`
}

func (e *EdgeChannelState) ToMap() map[string]interface{} {
	return map[string]interface{}{
		"params":              e.Params.ToMap(),
		"lastMetricData":      metricDataToMap(e.LastMetricData),
		"lastEdgeChannelData": edgeChannelDataToMap(e.LastEdgeChannelData),
	}
}

func mapToEdgeChannelState(m map[string]interface{}) (EdgeChannelState, error) {
	pm, err := coerce.ToObject(m["params"])
	if err != nil {
		return EdgeChannelState{}, err
	}
	params, err := mapToEdgeChannelParams(pm)
	if err != nil {
		return EdgeChannelState{}, err
	}
	mdm, err := coerce.ToObject(m["lastMetricData"])
	if err != nil {
		return EdgeChannelState{}, err
	}
	lastMetricData, err := mapToMetricData(mdm)
	if err != nil {
		return EdgeChannelState{}, err
	}
	edm, err := coerce.ToObject(m["lastEdgeChannelData"])
	if err != nil {
		return EdgeChannelState{}, err
	}
	lastEdgeChannelData, err := mapToEdgeChannelData(edm)
	if err != nil {
		return EdgeChannelState{}, err
	}
	s := EdgeChannelState{
		Params:              params,
		LastMetricData:      &lastMetricData,
		LastEdgeChannelData: &lastEdgeChannelData,
	}
	return s, nil
}

func metricDataToMap(md *ms.MetricData) map[string]interface{} {
	if md == nil {
		return nil
	}
	return map[string]interface{}{
		"id":        md.ID,
		"timestamp": md.Timestamp,
		"value":     md.Value.Raw,
	}
}

func mapToMetricData(m map[string]interface{}) (ms.MetricData, error) {
	id, err := coerce.ToString(m["id"])
	if err != nil {
		return ms.MetricData{}, nil
	}
	timestamp, err := coerce.ToInt64(m["timestamp"])
	if err != nil {
		return ms.MetricData{}, nil
	}
	raw, err := coerce.ToString(m["value"])
	if err != nil {
		return ms.MetricData{}, nil
	}
	value := gjson.Parse(raw)
	d := ms.MetricData{
		ID:        id,
		Timestamp: timestamp,
		Value:     value,
	}
	return d, nil
}

func edgeChannelDataToMap(ed *ds.EdgeChannelData) map[string]interface{} {
	if ed == nil {
		return nil
	}
	return map[string]interface{}{
		"id":        ed.ID,
		"timestamp": ed.Timestamp,
		"value":     ed.Value.Raw,
	}
}

func mapToEdgeChannelData(m map[string]interface{}) (ds.EdgeChannelData, error) {
	id, err := coerce.ToString(m["id"])
	if err != nil {
		return ds.EdgeChannelData{}, nil
	}
	timestamp, err := coerce.ToInt64(m["timestamp"])
	if err != nil {
		return ds.EdgeChannelData{}, nil
	}
	raw, err := coerce.ToString(m["value"])
	if err != nil {
		return ds.EdgeChannelData{}, nil
	}
	value := gjson.Parse(raw)
	d := ds.EdgeChannelData{
		ID:        id,
		Timestamp: timestamp,
		Value:     value,
	}
	return d, nil
}
